//
//  AsyncSocketManager.m
//  高仿暴走斗图
//
//  Created by huangsongyao on 16/3/4.
//  Copyright © 2016年 huangsongyao. All rights reserved.
//

#import "AsyncSocketManager.h"
#import "NSData+Socket.h"
#import "AsyncSocketManager+RAC.h"
#import "AsyncSocket+RACSignal.h"

static AsyncSocketManager *asyncSocketManager;

@interface AsyncSocketManager ()<AsyncSocketDelegate>

@property (nonatomic, strong) RACSignal *rac_addConnectSignal;
@property (nonatomic, strong) RACSignal *rac_didDisconnectSignal;
@property (nonatomic, strong) RACSignal *rac_willDisconnectSignal;
@property (nonatomic, strong) RACSignal *rac_didReadDataSignal;
@property (nonatomic, strong) RACSignal *rac_didWriteDataSignal;
@property (nonatomic, strong) AsyncSocket *asyncSocket;

@end

@implementation AsyncSocketManager

+ (instancetype)shareInstance {
    // gcd单例
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        asyncSocketManager = [[AsyncSocketManager alloc] init];
    });
    return asyncSocketManager;
}

- (instancetype)init {
    
    if (self = [super init]) {
        
        self.subject = [RACSubject subject];
        self.asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];
        [self.asyncSocket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
    }
    return self;
}

#pragma mark - RAC To AsyncSocketDelegate

- (void)rac_socketDelegate {
    
    @weakify(self);
    //链接成功
    [[[self rac_addConnectToHostDelegateObserver] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDictionary *x) {
        @strongify(self);
        self.rac_addConnectSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            [subscriber sendNext:x];
            [subscriber sendCompleted];
            return nil;
        }];
        [self.rac_addConnectSignal subscribe:self.subject];
    }];
    
    //断开
    [[[self rac_addSocketDidDisconnectDelegateObserver] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(AsyncSocket *socket) {
    
        @strongify(self);
        self.rac_didDisconnectSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:socket];
            [subscriber sendCompleted];
            return nil;
        }];
    
        [self.rac_didDisconnectSignal subscribe:self.subject];
    }];
    
    //将要断开
    [[[self rac_addWillDisconnectDelegateObserver] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDictionary *x) {
        
        @strongify(self);
        self.rac_willDisconnectSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:x];
            [subscriber sendCompleted];
            return nil;
        }];
        
        [self.rac_willDisconnectSignal subscribe:self.subject];
    }];
    
    //读取数据
    [[[self rac_addDidReadDataDelegateObserver] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDictionary *x) {
        
        @strongify(self);
        self.rac_didReadDataSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:x];
            [subscriber sendCompleted];
            return nil;
        }];
        
        [self.rac_didReadDataSignal subscribe:self.subject];
    }];
    
    //写入数据(发送数据)
    [[[self rac_addDidWriteDataDelegateObserver] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDictionary *x) {
        
        @strongify(self)
        self.rac_didWriteDataSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:x];
            [subscriber sendCompleted];
            return nil;
        }];
        
        [self.rac_didWriteDataSignal subscribe:self.subject];
    }];
}

- (RACSignal *)rac_addConnectToHostDelegateObserver {
    
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[self rac_didConnectToHostForSocket:self.asyncSocket] subscribeNext:^(id x) {
            
            [subscriber sendNext:x];
            [subscriber sendCompleted];
        }];
        return nil;
    }];
}

- (RACSignal *)rac_addSocketDidDisconnectDelegateObserver {
    
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[self rac_onSocketDidDisconnectForSocket:self.asyncSocket] subscribeNext:^(id x) {
           
            [subscriber sendNext:x];
            [subscriber sendCompleted];
        }];
        return nil;
    }];
}

- (RACSignal *)rac_addWillDisconnectDelegateObserver {
    
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[self rac_willDisconnectForSocket:self.asyncSocket] subscribeNext:^(id x) {
            
            [subscriber sendNext:x];
            [subscriber sendCompleted];
        }];
        return nil;
    }];
}

- (RACSignal *)rac_addDidReadDataDelegateObserver {
    
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[self rac_didReadDataForSocket:self.asyncSocket] subscribeNext:^(id x) {
            
            [subscriber sendNext:x];
            [subscriber sendCompleted];
        }];
        
        return nil;
    }];
}


- (RACSignal *)rac_addDidWriteDataDelegateObserver {
    
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[self rac_didWriteDataForSocket:self.asyncSocket] subscribeNext:^(id x) {
            
            [subscriber sendNext:x];
            [subscriber sendCompleted];
        }];
        
        return nil;
    }];
}


#pragma mark - RAC To ConnectServer

/**
 *  链接服务器
 */
- (RACSignal *)connectServer {
    
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
       
        @strongify(self);
        [[[self rac_connectSocketServer] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSNumber *linkStatus) {
            kSocketLinksStatusType status = (kSocketLinksStatusType)[linkStatus integerValue];
            switch (status) {
                case kSocketLinksStatusTypeLinksFailure: {
                    
                    [HSYHUDHelper showHUDViewForShowType:kShowHUDViewTypeText text:HSYLOCALIZED(@"链接失败，请检查网络") hideAfter:HUD_STRING_DISPLAY_TIME];
                }
                    break;
                case kSocketLinksStatusTypeLinksSuccess: {
                    
                    [subscriber sendNext:linkStatus];
                    [subscriber sendCompleted];
                }
                    
                default:
                    break;
            }
        }];
        return nil;
    }];
}


#pragma mark - RAC To Create Socket

/**
 *  创建socket链接
 *
 *  @return rac 信号
 */
- (RACSignal *)rac_createSocketLongLinks {
    
    if (!self.asyncSocket) {
        self.asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];
        [self.asyncSocket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
    }
    
    //先断开在链接，保证不是已连接状态
    [self socketDisconnectLinks];
    
    NSError *error = nil;
    BOOL isConnect = [self.asyncSocket connectToHost:SOCKET_HOST onPort:(UInt16)SOCKET_PORT error:&error];
    [self rac_socketDelegate];
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        if (isConnect) {
            [subscriber sendNext:@(kSocketLinksStatusTypeLinksSuccess)];
            [subscriber sendCompleted];
        } else {
            [subscriber sendNext:@(kSocketLinksStatusTypeLinksFailure)];
            [subscriber sendError:error];
            [subscriber sendCompleted];
        }
        return nil;
    }];
}


#pragma mark - RAC To Socket Operations

/**
 *  socket断开
 */
- (void)socketDisconnectLinks {
    
    if([self.asyncSocket isConnected]) {
        
        self.asyncSocket.userData = kSocketLinksStatusTypeUserDisconnect;       //声明是由用户主动切断
        [self.asyncSocket disconnect];                                          //立即断开socket链接状态
        
    } else {
        self.asyncSocket.userData = kSocketLinksStatusTypeNetDisconnect;        //声明是网络问题
    }
}


/**
 *  socket链接服务器
 *
 *  @return rac 信号
 */
- (RACSignal *)rac_connectSocketServer {
    
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        @strongify(self);
        [[[self rac_createSocketLongLinks] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) {
            [subscriber sendNext:x];
            [subscriber sendCompleted];
        }];
        return nil;
    }];
}


- (RACSignal *)sendHeartbeatToSocketServerWithJSONModel:(HSYSocketDataJSONModel *)jsonModel {
    
    NSData *socketData = [NSData convertSocketInfoToDataWithJSONModel:jsonModel];
    if (!socketData) {
        return nil;
    }
    
    BOOL isDisconnet = [self.asyncSocket isConnected];
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
       
        if (isDisconnet && self.asyncSocket.userData == kSocketLinksStatusTypeLinksSuccess) {
            
            [self.asyncSocket writeData:socketData withTimeout:-1 tag:(long long)kSocketLinksStatusTypeNetDisconnect];
        } else {
            
            [self socketDisconnectLinks];
        }
        return nil;
    }];
}


@end
